package com.onpositive.data.serializer.writers;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;

import com.onpositive.data.serializer.readers.DefaultReaderFactory;

public class StringIterableWriter extends AbstractWriter<Iterable<String>> {

	public static final int DIRECT_STORE = 1;
	public static final int INDIRECT_STORE = 2;
	
	ArrayList<String> storage = new ArrayList<String>() ;
	ArrayList<Integer> fileOffsets ;
	ArrayList<Integer> indexSequence = new ArrayList<Integer>() ;
	HashMap<String, Integer> map = new HashMap<String, Integer>() ;
	
	@SuppressWarnings("unchecked")
	public StringIterableWriter()
	{
		super( (Class) Iterable.class );
		fileOffsets = new ArrayList<Integer>() ;
		fileOffsets.add(0) ;
		storage.add("");
	}

	public void append( Iterable<String> strArr ) {
		
		if( strArr != null )
		{
			for( String str : strArr )
			{		
				str = str != null ? str : "" ;
				Integer ind = map.get( str ) ;
				
				if( ind == null )
				{
					ind = storage.size() ;
					storage.add( str ) ;
					map.put( str, ind ) ;
				}
				
				indexSequence.add( ind ) ;
			}
		}
		fileOffsets.add( indexSequence.size() ) ;
	}

	@Override
	protected void doSerialize()
	{
		int l1 = INT_SIZE*( indexSequence.size() + fileOffsets.size() + 2 ) ;
		int l2 = INT_SIZE*( indexSequence.size() + storage.size() + fileOffsets.size() + 2 );
	
		try{
			for( Integer i : indexSequence ) {
				String str = storage.get(i);
				if( str == null )
					str = "" ;
				l1 += ( 2 + str.getBytes("UTF-8").length ) ;
			}
		
			for( String s : storage ){
				s = s != null ? s : "" ;
				l2 += ( 2 + s.getBytes("UTF-8").length ) ;
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
			
		if( l2 > l1 )
		{			
			ArrayList<Integer> offsets = new ArrayList<Integer>( indexSequence.size() + 1 ) ;			
			int sizeInBytes = 0 ;
			offsets.add( sizeInBytes ) ;
			
			try{
				for( Integer i : indexSequence ) {
					String s = storage.get(i);
					s = s != null ? s : "" ;
					offsets.add( sizeInBytes += ( 2+s.getBytes("UTF-8").length ) ) ;
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			
			
			sizeInBytes += super.getDataOffset() + INT_SIZE * ( 5 + offsets.size() + fileOffsets.size() ) ;
			
			super.writeIntToStream( sizeInBytes ) ;
			super.writeIntToStream( DIRECT_STORE ) ;
			super.writeIntToStream( fileOffsets.size() ) ;
			super.writeIntToStream( indexSequence.size() ) ;
			super.writeIntToStream( Integer.MAX_VALUE ) ;//just to normalize output
			
			int dataOffset = super.getDataOffset() + INT_SIZE * ( offsets.size() + fileOffsets.size() ) ;
			for( Integer i : offsets )
				super.writeIntToStream( i + dataOffset ) ;
			
			for( Integer i : fileOffsets )
				super.writeIntToStream( i ) ;
			
			for( Integer i : indexSequence ) {
				String s = storage.get(i);
				s = s != null ? s : "" ;
				super.writeStringUTFToStream( s ) ;
			}
		}
		else{
			
			ArrayList<Integer> offsets = new ArrayList<Integer>( storage.size() + 1 ) ;			
			int sizeInBytes = 0 ;
			offsets.add( sizeInBytes ) ;
			
			try {
				for( String s : storage ){
					s = s != null ? s : "" ;
					offsets.add( sizeInBytes += ( 2 + s.getBytes("UTF-8").length )  ) ;
				}
			
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			
			sizeInBytes += ( super.getDataOffset() + INT_SIZE * ( 5 + indexSequence.size() + offsets.size() + fileOffsets.size() ) );

			super.writeIntToStream( sizeInBytes ) ;
			super.writeIntToStream( INDIRECT_STORE ) ;
			super.writeIntToStream( fileOffsets.size() ) ;
			super.writeIntToStream( indexSequence.size() ) ;
			super.writeIntToStream( storage.size() ) ;
			
			int dataOffset = super.getDataOffset() + INT_SIZE * ( indexSequence.size() + offsets.size() + fileOffsets.size() ) ;
			for( Integer i : offsets )
				super.writeIntToStream( i + dataOffset ) ;
			
			for( Integer i : fileOffsets )
				super.writeIntToStream( i ) ;
			
			for( Integer i : indexSequence )
				super.writeIntToStream( i ) ;			
			
			for( String s : storage ){
				s = s != null ? s : "" ;
				super.writeStringUTFToStream( s ) ;
			}
		}
	}
	
	@Override
	protected int getID()
	{
		return DefaultReaderFactory.RW_ID_STRING_ITERABLE ;				
	}
}

